<?php
class cpTemplate
{
	public $tplFile;//模板文件
	public $cacheFile;//模板缓存文件
	public $vars=array();//存放变量信息
	public $config=array();//存放配置信息

	public function __construct($config=array())
	{
		$this->config['TPL_TEMPLATE_PATH']=isset($config['TPL_TEMPLATE_PATH'])?$config['TPL_TEMPLATE_PATH']:'./template/';//模板目录
		$this->config['TPL_TEMPLATE_SUFFIX']=isset($config['TPL_TEMPLATE_SUFFIX'])?$config['TPL_TEMPLATE_SUFFIX']:'.html';//模板后缀
		$this->config['TPL_CACHE_ON']=isset($config['TPL_CACHE_ON'])?$config['TPL_CACHE_ON']:true;//是否开启模板缓存，true开启
		$this->config['TPL_CACHE_PATH']=isset($config['TPL_CACHE_PATH'])?$config['TPL_CACHE_PATH']:'./data/tpl_chache/';//模板缓存目录
		$this->config['TPL_CACHFILE_SUFFIX']=isset($config['TPL_CACHFILE_SUFFIX'])?$config['TPL_CACHFILE_SUFFIX']:'.php';//模板缓存后缀
		
		//模板目录和模板缓存目录，如果不是以“/”,则加上"/"
        if(substr($this->config['TPL_TEMPLATE_PATH'], -1) != "/")    
		{
			$this->config['TPL_TEMPLATE_PATH'] .= "/";
		}
	    if(substr($this->config['TPL_CACHE_PATH'], -1) != "/")    
		{
			$this->config['TPL_CACHE_PATH'] .= "/";
		}
		
		//检查模板目录是否存在
		if((!file_exists($this->config['TPL_TEMPLATE_PATH']))||(!is_dir($this->config['TPL_TEMPLATE_PATH']))) 
		{
			$this->error($this->config['TPL_TEMPLATE_PATH']."模板目录不存在");
		}
		
		//模板缓存开启，检查是否存在模板缓存目录，没有则创建
		if($this->config['TPL_CACHE_ON'])
		{
		
			if((!file_exists($this->config['TPL_CACHE_PATH']))||(!is_dir($this->config['TPL_CACHE_PATH'])))
			{
				//模板缓存目录
				if (!@mkdir($this->config['TPL_CACHE_PATH'],0777))
				 {
					 $this->error($this->config['TPL_CACHE_PATH']."模板缓存目录不存在");
				 }
			}
			else 
			{	
				//模板缓存开启，检查模板缓存目录是否可写，不可写，则修改属性
				if(!is_writable($this->config['TPL_CACHE_PATH']))
				{
					//修改模板缓存属性，设置为可写
					if(!@chmod($this->config['TPL_CACHE_PATH'],0777))
					{
						$this->error($this->config['TPL_CACHE_PATH']."模板缓存目录不可写");
					}
				}
			}
		}
	}
	
	protected function init($tpl)
	{
		$this->tplFile=$this->config['TPL_TEMPLATE_PATH'].$tpl.$this->config['TPL_TEMPLATE_SUFFIX'];
		$this->cacheFile=$this->config['TPL_CACHE_PATH'].md5($this->config['TPL_CACHE_PATH'].$tpl).$this->config['TPL_CACHFILE_SUFFIX'];
		if(!file_exists($this->tplFile)|| !is_file($this->tplFile)) 
		{
			$this->error($this->tplFile."模板不存在");
		}
		return false;
	}
	
	//模板编译内核
	protected  function compile()
	{
		$template = file_get_contents($this->tplFile);
		//常量解析
		$template=str_replace("__ROOT__","<?php echo __ROOT__; ?>",$template);
		$template=str_replace("__PUBLIC__","<?php echo __PUBLIC__; ?>",$template);
		$template=str_replace("__APP__","<?php echo __APP__; ?>",$template);
		$template=str_replace("__URL__","<?php echo __URL__; ?>",$template);
		
		$template = preg_replace("/{(\\$[a-zA-Z_]\w*(?:\[[\w\.\"\'\[\]\$]+\])*)}/i", "<?php if(isset($1)) echo $1; ?>", $template);//替换变量
		
	    $template= preg_replace("/{include\s*file=\"(.*)\"}/ie", "\$this->getTemplate('$1')", $template);//递归解析模板包含
		
		return $template;
	}
	//获取模板，并编译
	protected  function getTemplate($tpl)
	{
		$this->tplFile=$this->config['TPL_TEMPLATE_PATH'].$tpl.$this->config['TPL_TEMPLATE_SUFFIX'];
		return $this->compile();
	}
	
	//模板赋值
	public function assign($name, $value)
	{
		$this->vars[$name] = $value;
	}

	//执行模板解析输出
	public function display($tpl='')
	{
		//如果没有设置模板，则调用当前模块的当前操作模板
		if(($tpl=="")&&(!empty($_GET['_module']))&&(!empty($_GET['_action'])))
		{
			$tpl=$_GET['_module']."/".$_GET['_action'];
		}
		
		$this->init($tpl);
		//解析变量
		extract($this->vars, EXTR_OVERWRITE);
		define('CANPHP',true);
		
		//如果开启了模板缓存，则检查模板缓存
		if($this->config['TPL_CACHE_ON']&&file_exists($this->cacheFile)&&is_file($this->cacheFile)) 
		{
			if(filemtime($this->cacheFile)>=filemtime($this->tplFile))
			{
				require($this->cacheFile);//存在模板缓存，且没有过期，则直接输出
				return true;
			}
		}
		
		$template= $this->getTemplate($tpl);//获取经编译后的内容
		//如果开启缓存，则写入缓存，否则直接输出
		if($this->config['TPL_CACHE_ON'])
		{
			file_put_contents($this->cacheFile,"<?php if(!defined('CANPHP')) exit;?>".$template);//写入缓存
			require($this->cacheFile);//执行编译后模板输出
		}
		else
		{
			eval('?>'.$template);//直接执行编译后的模板输出
		}		
	}	
	
    //输出错误信息
	public function error($str)
	{
		require_once(dirname(__FILE__).'/cpError.class.php');
		cpError::show($str);
	}

}